package panda.client.listeners;

import java.util.List;

import panda.client.Cardpanda;
import panda.client.ui.widgets.Bin;
import panda.client.ui.widgets.Counter;
import panda.client.ui.widgets.NoteTip;
import panda.client.ui.widgets.Tooltip;

import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.DeferredCommand;
import com.google.gwt.user.client.ui.MouseListener;
import com.google.gwt.user.client.ui.Widget;

public class CounterDragListener implements MouseListener {
	private int xOffset; // position in source widget where mouse is before dragging
	private int yOffset;

	public void onMouseDown(Widget src, int x, int y) {
		Counter target = (Counter) src;
		DOM.eventPreventDefault(DOM.eventGetCurrentEvent());
		target.addStyleName("mouseStyle-dragging");

		DOM.setCapture(target.getElement());
		target.setDragging(true);
		xOffset = x;
		yOffset = y;
	}

	public void onMouseMove(final Widget src, int x, int y) {
		DOM.eventPreventDefault(DOM.eventGetCurrentEvent());
		Counter counter = (Counter) src;
		int xAbs = x + src.getAbsoluteLeft() - Cardpanda.canvas.getAbsoluteLeft();
		int yAbs = y + src.getAbsoluteTop() - Cardpanda.canvas.getAbsoluteTop();

		if(counter.isDragging()) {
			setBinHover(counter, x, y);
			Cardpanda.canvas.setWidgetPosition(src, xAbs - xOffset, yAbs - yOffset);
		}
	}
	
	/* setBinHover if this card is dragged over a bin */
	private void setBinHover(Counter counter, int x, int y) {
		final List<Bin> bins = Cardpanda.clientModel.getBinsThisClientControls();
		for(Bin bin : bins) {
			if(withinBinCoordinates(counter, bin, x, y)) {
				bin.setHover();
			} else {
				bin.removeHover();
			}
		}
	}
	
	/**
	 * Remove the drag style.<br>
	 * If this counter is over a bin, remove it from the game<br>
	 * Update the server.
	 */
	public void onMouseUp(Widget src, int x, int y) {		
		Counter counter = (Counter) src;
		src.removeStyleName("mouseStyle-dragging");
		DOM.releaseCapture(src.getElement());
		counter.setDragging(false);
		
		List<Bin> bins = Cardpanda.clientModel.getBinsThisClientControls();
		Bin targetBin = null;
		int numBinsUnderCounter = 0; /* number of bins this card is hovering over */
		boolean binUnderCounterFound = false;

		for(Bin bin : bins) {
			if(withinBinCoordinates(counter, bin, x, y)) {
				numBinsUnderCounter++;
				binUnderCounterFound = true;
				targetBin = bin;
			}
		}
		
		assert numBinsUnderCounter < 2 : "There shouldn't be more than 1 bin this counter is hovering over";

		if(binUnderCounterFound) {
			String logForMe = "You remove a counter from the game. "/* + bin.getOwnerName() + bin.getName() */;
			String logForOthers = Cardpanda.clientModel.getSessionID().getName() + " removes a counter from the game.";
			NoteTip.get().log(logForMe, logForOthers);
			Cardpanda.clientModel.removeCounter(counter);

			targetBin.removeHover();
			DeferredCommand.addCommand(new Command() {
				public void execute() {
					Tooltip.get().hide(); /* counters the showTooltip method in tooltipListener's onmouseup */
				}
			});		
		} else {
			int counterx = src.getAbsoluteLeft() - Cardpanda.canvas.getAbsoluteLeft();
			int countery = src.getAbsoluteTop() - Cardpanda.canvas.getAbsoluteTop();
			String logForMe = "You move a counter to " + "(" + counterx + ", " + countery + ").";
			String logForOthers = Cardpanda.clientModel.getSessionID().getName() + " moves a counter to " + "("
					+ counterx + ", " + countery + ").";
			NoteTip.get().log(logForMe, logForOthers);
		}

		Cardpanda.sendModelUpdateToServer(Cardpanda.clientModel.getSessionID());
	}
	
	/** Returns true if the mouse is positioned over target bin. */
	private boolean withinBinCoordinates(Counter counter, Bin bin, int x, int y) {
		/* Bounds = absolute coordinates of mouse cursor */
		int xBound = counter.getAbsoluteLeft() - Cardpanda.canvas.getAbsoluteLeft() + x;
		int yBound = counter.getAbsoluteTop() - Cardpanda.canvas.getAbsoluteTop() + y;

		/* The bin's 4 corners lie on xLeft xRight yTop yBottom. */
		/* Note: these absolute positions rely on the canvas's absolute left and top as well. */
		int xLeft = bin.getLabel().getAbsoluteLeft() - Cardpanda.canvas.getAbsoluteLeft();
		int yTop = bin.getLabel().getAbsoluteTop() - Cardpanda.canvas.getAbsoluteTop();
		int yBottom = bin.getLabel().getAbsoluteTop() + bin.getHeight() - Cardpanda.canvas.getAbsoluteTop();
		int xRight = bin.getLabel().getAbsoluteLeft() + bin.getWidth() - Cardpanda.canvas.getAbsoluteLeft();

		return xBound >= xLeft && xBound <= xRight && yBound >= yTop && yBound <= yBottom;
	}

	public void onMouseEnter(Widget src) {
		src.addStyleName("mouseStyle-mouseover");
		Cardpanda.focusPnl.setFocus(true);
	}

	public void onMouseLeave(Widget src) {
		src.removeStyleName("mouseStyle-mouseover");
	}
}